home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 19 / CU Amiga Magazine's Super CD-ROM 19 (1998)(EMAP Images)(GB)[!][issue 1998-02].iso / CUCD / Programming / LEDA / source / src / plane / _polygon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  6.7 KB  |  330 lines

  1. /*******************************************************************************
  2. +
  3. +  LEDA  3.1c
  4. +
  5. +
  6. +  _polygon.c
  7. +
  8. +
  9. +  Copyright (c) 1994  by  Max-Planck-Institut fuer Informatik
  10. +  Im Stadtwald, 6600 Saarbruecken, FRG     
  11. +  All rights reserved.
  12. *******************************************************************************/
  13.  
  14.  
  15.  
  16. #include <LEDA/polygon.h>
  17. #include <LEDA/sweep_segments.h>
  18. #include <math.h>
  19.  
  20.  
  21. //------------------------------------------------------------------------------
  22. // polygons
  23. //------------------------------------------------------------------------------
  24.  
  25.  
  26. polygon::polygon()  { PTR = new polygon_rep; }
  27.  
  28.  
  29. ostream& operator<<(ostream& out, const polygon& p) 
  30. { p.vertices().print(out);
  31.   return out;
  32.  } 
  33.  
  34. istream& operator>>(istream& in,  polygon& p) 
  35. { list<point> L; 
  36.   L.read(in); 
  37.   p = polygon(L); 
  38.   return in;
  39. }
  40.  
  41.  
  42. static void polygon_check(const list<segment>&);
  43.  
  44. polygon::polygon(const list<point>& pl, bool check)
  45. { PTR = new polygon_rep;
  46.  
  47.   list_item it,it1;
  48.  
  49.   forall_list_items(it,pl)
  50.   { it1 = pl.cyclic_succ(it);
  51.     ptr()->seg_list.append(segment(pl[it],pl[it1]));
  52.    }
  53.  
  54.   if (check) polygon_check(ptr()->seg_list);
  55. }
  56.  
  57. list<point> polygon::vertices() const
  58. { list<point> result;
  59.   segment s;
  60.   forall(s,ptr()->seg_list) result.append(s.start());
  61.   return result;
  62. }
  63.  
  64.  
  65.  
  66.  
  67. static void polygon_check(const list<segment>& seg_list)
  68. {  if (seg_list.length() < 3) 
  69.      error_handler(1,"polygon: must be simple");
  70.  
  71.    list<point> L;
  72.    SWEEP_SEGMENTS(seg_list,L);
  73.  
  74.   if (L.length() != seg_list.length())
  75.    error_handler(1,"polygon: must be simple");
  76.  
  77.   list_item it;
  78.  
  79.   double angle = 0;
  80.  
  81.   forall_list_items(it,seg_list)
  82.   { list_item succ = seg_list.cyclic_succ(it);
  83.     segment s1 = seg_list[it];
  84.     segment s2 = seg_list[succ];
  85.     angle += s1.angle(s2);
  86.    }
  87.  
  88.   if (angle > 0)
  89.    error_handler(1,"polygon: point list must be clockwise oriented.");
  90. }
  91.  
  92. polygon polygon::translate(double alpha, double d) const
  93. { list<point> L;
  94.   segment s;
  95.   forall(s,ptr()->seg_list) L.append(s.start().translate(alpha,d));
  96.   return polygon(L,false);
  97. }
  98.  
  99. polygon polygon::translate(const vector& v) const
  100. { list<point> L;
  101.   segment s;
  102.   forall(s,ptr()->seg_list) L.append(s.start().translate(v));
  103.   return polygon(L,false);
  104. }
  105.  
  106. polygon polygon::rotate(const point& origin, double alpha) const
  107. { list<point> L;
  108.   segment s;
  109.   forall(s,ptr()->seg_list) L.append(s.start().rotate(origin,alpha));
  110.   return polygon(L,false);
  111. }
  112.  
  113. polygon polygon::rotate(double alpha) const
  114. { return rotate(point(0,0),alpha);
  115.  }
  116.  
  117.  
  118.  
  119. bool polygon::inside(const point& p) const
  120. {
  121.   line l(p,M_PI_2);  // vertical line through p
  122.  
  123.   int count = 0;
  124.  
  125.   segment s;
  126.   forall(s,ptr()->seg_list)
  127.   { point q;
  128.     if (!l.intersection(s,q)) continue;
  129.     if (q.ycoord() < p.ycoord()) continue;
  130.     if (q == s.start())  continue;
  131.     if (q == s.end())  continue;
  132.     count++ ;
  133.    }
  134.  
  135.   list<point> plist = vertices();
  136.  
  137.   list_item i0 = plist.first();
  138.  
  139.   while (plist[i0].xcoord() == p.xcoord())  i0 = plist.cyclic_pred(i0);
  140.  
  141.   list_item i = plist.cyclic_succ(i0);
  142.  
  143.   for(;;)
  144.   { 
  145.     while ( i != i0 && (plist[i].xcoord() != p.xcoord() || 
  146.                         plist[i].ycoord() < p.ycoord()    )  )
  147.        i = plist.cyclic_succ(i);
  148.  
  149.     if (i==i0) break;
  150.  
  151.     point q  = plist[i];
  152.     point q0 = plist[plist.cyclic_pred(i)];
  153.  
  154.     while ((plist[i].xcoord()==p.xcoord()) && (plist[i].ycoord() >= p.ycoord()))
  155.     { if (plist[i]==p) return true;
  156.       i = plist.cyclic_succ(i);
  157.      }
  158.  
  159.     point q1 = plist[i];
  160.  
  161.      if (q0.xcoord() < p.xcoord() && q1.xcoord() > p.xcoord()) count++;
  162.       if (q0.xcoord() > p.xcoord() && q1.xcoord() < p.xcoord()) count++;
  163.  
  164.    }
  165.  
  166.    return count%2;
  167.  
  168. }
  169.  
  170.  
  171.  
  172. bool polygon::outside(const point& p) const { return !inside(p); }
  173.  
  174.  
  175.  
  176. list<point> polygon::intersection(const segment& s) const
  177. { list<point> result;
  178.   segment t;
  179.   point p;
  180.  
  181.   forall(t,ptr()->seg_list) 
  182.     if (s.intersection(t,p))
  183.      if (result.empty()) result.append(p);
  184.      else if (p != result.tail() ) result.append(p);
  185.  
  186.   return result;
  187. }
  188.  
  189.  
  190. list<point> polygon::intersection(const line& l) const
  191. { list<point> result;
  192.   segment t;
  193.   point p;
  194.  
  195.   forall(t,ptr()->seg_list) 
  196.     if (l.intersection(t,p))
  197.      if (result.empty()) result.append(p);
  198.      else if (p != result.tail() ) result.append(p);
  199.  
  200.   return result;
  201. }
  202.  
  203.  
  204. // intersection with polygon
  205.  
  206. static bool polygon_test_edge(GRAPH<point,int>& G,edge& i1)
  207. { node v = G.target(i1);
  208.  
  209.   edge e,i2=nil,o1=nil,o2=nil;
  210.  
  211.   forall_adj_edges(e,v)
  212.     if (e != i1)
  213.     { if (v==target(e)) i2 = e;
  214.       else if (G[e]== G[i1]) o1 = e;
  215.            else o2 = e;
  216.      }
  217.  
  218.   if (i2==nil) return false;
  219.  
  220.   segment si1(G[source(i1)],G[v]);
  221.   segment si2(G[v],G[source(i2)]);
  222.   segment so2(G[v],G[target(o2)]);
  223.  
  224.   double alpha = si1.angle(si2);
  225.   double beta  = si1.angle(so2);
  226.  
  227.   return (alpha > beta);
  228.  
  229. }
  230.  
  231.  
  232.  
  233. static edge polygon_switch_edge(GRAPH<point,int>& G,edge i1)
  234. { node v = G.target(i1);
  235.  
  236.   edge e,i2=nil,o1=nil,o2=nil;
  237.  
  238.   forall_adj_edges(e,v)
  239.     if (e != i1)
  240.     { if (v==target(e)) i2 = e;
  241.       else if (G[e]== G[i1]) o1 = e;
  242.            else o2 = e;
  243.      }
  244.  
  245.   if (i2==nil) return  o1;
  246.  
  247.   segment si1(G[source(i1)],G[v]);
  248.   segment si2(G[v],G[source(i2)]);
  249.   segment so1(G[v],G[target(o1)]);
  250.   segment so2(G[v],G[target(o2)]);
  251.  
  252.   double alpha = si1.angle(si2);
  253.   double beta  = si1.angle(so2);
  254.   double gamma = si1.angle(so1);
  255.  
  256.   if (alpha < beta) cout << "error: alpa < beta!!\n";
  257.  
  258.   if (gamma >= beta) return o2;
  259.   else return o1;
  260.  
  261. }
  262.  
  263.  
  264. list_polygon_ polygon::intersection(const polygon& P) const
  265. {
  266.  
  267.   list<polygon> result;
  268.  
  269.   GRAPH<point,int> SUB;
  270.  
  271.   SWEEP_SEGMENTS(segments(),P.segments(),SUB);
  272.  
  273.   int N = SUB.number_of_nodes();
  274.  
  275.   if (N < size() + P.size())
  276.    error_handler(1,"polygon: sorry, internal error in intersection");
  277.  
  278.   if (N == size() + P.size())
  279.   { // no intersections between edges of (*this) and P
  280.     // check for inclusion
  281.  
  282.     segment s1 = ptr()->seg_list.head();
  283.     segment s2 = P.ptr()->seg_list.head();
  284.     point   p1 = s1.start();
  285.     point   p2 = s2.start();
  286.  
  287.     if (P.inside(p1))                     // (*this) is conained in P
  288.       result.append(*this);
  289.     else
  290.       if (inside(p2))                     // P is conained in (*this)
  291.         result.append(P);                   
  292.  
  293.  
  294.     return result;
  295.  
  296.    }
  297.  
  298.   SUB.make_undirected();
  299.  
  300.   edge e;
  301.  
  302.   list<point> PL;
  303.  
  304.   edge_array<bool> marked(SUB,false);
  305.  
  306.   forall_edges(e,SUB) 
  307.   { edge f;
  308.     if (!marked[e]  && SUB.outdeg(target(e))>1) 
  309.       if (polygon_test_edge(SUB,e))
  310.       { // new polygon found
  311.        marked[e] = true;
  312.        PL.append(SUB[source(e)]);
  313.        f = polygon_switch_edge(SUB,e);
  314.        while (f!=e)
  315.        { marked[f] = true;
  316.          PL.append(SUB[source(f)]);
  317.          f = polygon_switch_edge(SUB,f);
  318.         }
  319.        result.append(polygon(PL,false));
  320.        PL.clear();
  321.       }
  322.   }
  323.  
  324.  SUB.make_directed();
  325.  
  326.  return result;
  327.  
  328. }
  329.